#ifndef __M_LOOP_H__
#define __M_LOOP_H__

#include "buffer.hpp"
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <memory>
#include <atomic>
namespace log
{
    using func_t = std::function<void(Buffer &)>;
    enum class AsyncType
    {
        ASYNC_SAFE,  // 安全状态，表示缓冲区满了阻塞，避免资源耗尽
        ASYNC_UNSAFE // 不考虑资源耗尽，无限扩容（常用于测试）
    };
    class AsyncLooper
    {
    public:
        using ptr = std::shared_ptr<AsyncLooper>;
        AsyncLooper(const func_t &cb,AsyncType type = AsyncType::ASYNC_SAFE) : 
        _looper_type(type), _stop(false), _thread(std::thread(&AsyncLooper::threadEntry, this)),_callBack(cb) {}
        ~AsyncLooper()
        {
            stop();
        }
        void stop()
        {
            _stop = true;
            _cond_con.notify_all(); // 唤醒所有的工作线程
            _thread.join();         // 等待所有工作线程退出
        }
        void push(const char *data, size_t len)
        {
            // 1.无限扩容-非安全 2.固定大小 --生产缓冲区满就阻塞
            std::unique_lock<std::mutex> lock(_mutex);
            // 条件变量控制,若缓冲区剩余空间大小大于数据长度，则可以添加数据
            if (_looper_type == AsyncType::ASYNC_SAFE)
                _cond_pro.wait(lock, [&](){ return _pro_buf.writeableSize() >= len; });
            // 能走下来代表满足条件，可以向缓冲区添加数据
            _pro_buf.push(data, len);
            // 唤醒消费者对缓冲区数据进行处理
            _cond_con.notify_one();
        }

    private:
        // 线程入口函数 --对对消费缓冲区进行数据处理，处理完毕后，初始化缓冲区，交换缓冲区
        void threadEntry()
        {
            while (1)
            {
                // 1.判断生产缓冲区有没有数据，有则交换，无则阻塞
                // 为互斥锁设置一个生命周期，当缓冲区交换完毕后就解锁（不用对数据处理过程加锁保护）
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    //退出标记被标记,且生产缓冲区无数据后在，才退出
                    if(_stop&&_pro_buf.empty())break;
                    // 若退出前被唤醒，或者有数据被唤醒，返回真，继续向下运行，否者重新陷入阻塞
                    _cond_con.wait(lock, [&]()
                                   { return _stop || !_pro_buf.empty(); });
                    //
                    _con_buf.swap(_pro_buf);
                    // 2.唤醒生产者
                    if (_looper_type == AsyncType::ASYNC_SAFE)
                        _cond_pro.notify_all();
                }
                // 2.被唤醒后，对消费缓冲区进行数据处理
                _callBack(_con_buf);
                // 3.初始化消费缓冲区
                _con_buf.reset();
            }
        }

    private:
        func_t _callBack; // 具体对缓冲区数据进行处理的回调函数，由异步日志器使用者提供
    private:
        log::AsyncType _looper_type;
        std::atomic<bool> _stop; // 原子类型防止同时操作 工作器停止标记
        Buffer _pro_buf;         // 生产缓冲区
        Buffer _con_buf;         // 消费缓冲区
        std::mutex _mutex;
        std::condition_variable _cond_pro; // 生产者环境变量
        std::condition_variable _cond_con; // 生产者环境变量
        std::thread _thread;               // 异步工作器对应的工作线程
    };
}
#endif